﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="SettingDescriptorAttribute.cs" company="Radical Research Ltd">
//   Copyright (c) Radical Research Ltd. The MIT License (MIT)
// </copyright>
// <summary>
//   Declarative descriptor definitions
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace RadicalResearch.MiniState.Attributes
{
    using System;
    using System.Reflection;

    using RadicalResearch.MiniState.Descriptors;

    /// <summary>Declarative descriptor definitions</summary>
    [AttributeUsage(AttributeTargets.Property)]
    public class SettingDescriptorAttribute : Attribute
    {
        #region Constants and Fields

        /// <summary>
        ///   flag if the setting validated using hash validation.
        /// </summary>
        private readonly bool isValidated;

        /// <summary>
        ///   Setting Key
        /// </summary>
        private readonly string settingKey;

        /// <summary>
        ///   Value Key used in the value collection
        /// </summary>
        private readonly string valueKey;

        #endregion

        #region Constructors and Destructors

        /// <summary>
        ///   Initializes a new instance of the <see cref = "SettingDescriptorAttribute" /> class.
        /// </summary>
        public SettingDescriptorAttribute()
            : this(null, false)
        {
        }

        /// <summary>Initializes a new instance of the <see cref="SettingDescriptorAttribute"/> class.</summary>
        /// <param name="isValidated">if set to <c>true</c> if the setting validated using hash validation.</param>
        public SettingDescriptorAttribute(bool isValidated)
            : this(null, isValidated)
        {
        }

        /// <summary>Initializes a new instance of the <see cref="SettingDescriptorAttribute"/> class.</summary>
        /// <param name="settingKey">The setting key.</param>
        /// <param name="isValidated">if set to <c>true</c> if the setting validated using hash validation.</param>
        public SettingDescriptorAttribute(string settingKey, bool isValidated)
            : this(settingKey, settingKey, isValidated)
        {
        }

        /// <summary>Initializes a new instance of the <see cref="SettingDescriptorAttribute"/> class.</summary>
        /// <param name="settingKey">The setting key.</param>
        /// <param name="valueKey">The value key.</param>
        /// <param name="isValidated">if set to <c>true</c> if the setting validated using hash validation.</param>
        public SettingDescriptorAttribute(string settingKey, string valueKey, bool isValidated)
        {
            this.settingKey = settingKey;
            this.valueKey = valueKey;
            this.isValidated = isValidated;
        }

        #endregion

        #region Properties

        /// <summary>
        ///   Gets the setting key.
        /// </summary>
        public string SettingKey
        {
            get
            {
                return this.settingKey;
            }
        }

        /// <summary>
        ///   Gets a value indicating whether this instance is validated.
        /// </summary>
        /// <value>
        ///   <c>true</c> if this setting is validated using hash validation; otherwise, <c>false</c>.
        /// </value>
        protected bool IsValidated
        {
            get
            {
                return this.isValidated;
            }
        }

        /// <summary>
        ///   Gets the value key.
        /// </summary>
        protected string ValueKey
        {
            get
            {
                return this.valueKey;
            }
        }

        #endregion

        #region Methods

        /// <summary>Gets the descriptor.</summary>
        /// <returns>Setting descriptor for the specified property.</returns>
        internal SettingDescriptorBase GetDescriptor()
        {
            return this.GetDescriptor(null);
        }

        /// <summary>Gets the descriptor.</summary>
        /// <param name="property">The property.</param>
        /// <returns>Setting descriptor for the specified property.</returns>
        internal virtual SettingDescriptorBase GetDescriptor(PropertyInfo property)
        {
            string key = this.valueKey;
            if (string.IsNullOrEmpty(key))
            {
                key = property.Name;
            }

            if (property.PropertyType == typeof(string))
            {
                return new StringSettingDescriptor(key, this.isValidated);
            }

            if (property.PropertyType == typeof(byte) || property.PropertyType == typeof(short) ||
                property.PropertyType == typeof(int) || property.PropertyType == typeof(long) ||
                property.PropertyType == typeof(sbyte) || property.PropertyType == typeof(ushort) ||
                property.PropertyType == typeof(uint) || property.PropertyType == typeof(ulong))
            {
                return new NumericSettingDescriptor(key, this.isValidated, property.PropertyType);
            }

            if (property.PropertyType == typeof(bool))
            {
                return new BooleanSettingDescriptor(key, 0, BooleanSettingDescriptor.BitValueSize.SingleBit);
            }

            if (property.PropertyType == typeof(DateTime))
            {
                return new DateTimeSettingDescriptor(key, this.isValidated);
            }

            if (property.PropertyType.IsValueType)
            {
                return new ValueTypeSettingDescriptor(key, this.isValidated, property.PropertyType);
            }

            return null;
        }

        #endregion
    }
}